#include "tserverwidget.h"
#include <iostream>
#include <QDateTime>
#include <QDebug>
#include <hv/hloop.h>
#include <hv/hv.h>
#include <QFile>
#include <QIODevice>
#include <QTableWidget>
#include <QHeaderView>
#include <QTextEdit>
#include <QString>

TServerWidget::TServerWidget(QWidget *parent)
    : QMainWindow(parent)
    , m_pStart(new QPushButton(this))
    , m_pEnd(new QPushButton(this))
    , m_pHost(new QLabel(this))
    , m_pPort(new QLabel(this))
    , m_pHostLine(new QLineEdit(this))
    , m_pPortLine(new QLineEdit(this))
    , m_pTipsBox(new QTextEdit(this))
    , m_pClientMapWidget(new QTableWidget(this))
    , m_HeartBeatLoop(new hv::EventLoop)
{
    qRegisterMetaType<QTextCursor>("QTextCursor");
    qRegisterMetaType<QVector<int>>("QVector<int>");

    resize(500, 500);
    initUI();
    initConnect();
}

void TServerWidget::initConnect()
{
    connect(m_pStart, &QPushButton::released, this , [=]() {
        std::string host = m_pHostLine->text().toStdString();
        int port = m_pPortLine->text().toInt();
        if (start(port, host.c_str()))
        {
            m_pStart->setEnabled(false);
            m_pEnd->setEnabled(true);
            std::cout << "Server is running  " << host.c_str() << "  " << port << std::endl;
        }
        else
            std::cout << "Server runing failed" << std::endl;
        m_HeartBeatLoop = m_HeartBeatLoopThread.loop();
        m_HeartBeatLoop->setInterval(30000,[=](hv::TimerID){
            if(!clientMap.empty())
                checkHeartbeats();
        });
        m_HeartBeatLoopThread.start();
    });

    connect(m_pEnd, &QPushButton::released, this , [=](){
        if (!clientMap.empty())
        {
            for (const auto& client : clientMap)
            {
                client.second.channel->write("服务器已关闭");
                client.second.channel->close();
            }
            clientMap.clear();
            row = 0;
        }

        stop();
        incompleteMessageBuffer.clear();
        m_pClientMapWidget->clear();
        m_pStart->setEnabled(true);
        m_pEnd->setEnabled(false);
        std::cout << "Server Down!" << std::endl;
    });
}



bool TServerWidget::start(int port, const char* host)
{
    server = new hv::TcpServer;

   
    int listenfd = server->createsocket(port,host);
    if (listenfd < 0) {
        return false;
    }
    server->setThreadNum(1);

    server->onConnection = [](const hv::SocketChannelPtr& channel) {
        if (channel->isConnected()) {
            std::cout << channel->peeraddr().c_str() << "  connected! connfd=" << channel->fd() << std::endl;
        }
        else {
            std::cout << channel->peeraddr().c_str() << "  disconnected! connfd=" << channel->fd() << std::endl;
            // 删除断开连接的元素
            channel->close();
        }
    };


    server->onMessage = [this](const hv::SocketChannelPtr& channel, hv::Buffer* buf) { //接受消息

        incompleteMessageBuffer.append((char*)buf->data(), buf->size());
        if (incompleteMessageBuffer.size() < 4) {
            // 如果数据不足4字节，则无法读取消息头，等待更多数据
            std::cout << "等待消息头..." << std::endl;
            return;
        }

        // 从缓冲区中读取消息头
        uint32_t messageLength;
        memcpy(&messageLength, incompleteMessageBuffer.data(), 4);
        messageLength = (messageLength >> 24) |
            ((messageLength >> 8) & 0x0000FF00) |
            ((messageLength << 8) & 0x00FF0000) |
            (messageLength << 24); // 大端转小端

        std::cout << "消息头大小：" << messageLength << std::endl;
        // 检查缓冲区中是否有足够的数据来读取完整的消息体
        if (incompleteMessageBuffer.size() < (4 + messageLength)) {
            std::cout << "等待消息体..." << std::endl;
            return;
        }
        if (incompleteMessageBuffer.size() >= (4 + messageLength)) {
            std::cout << "数据接收完整" << std::endl;
        }
        std::string message(incompleteMessageBuffer.data() + 4, messageLength);
        
        incompleteMessageBuffer.erase(0, messageLength + 4);
        std::cout << "获取消息: " << message << "  from  " << channel->fd() << std::endl;
        //接受到outputString 反序列化数据获得json格式的数据，再获取其中的C++对象
        Json::CharReaderBuilder reader;
        Json::Value parsedRoot;
        std::string errs;
        std::istringstream s(message);
        cmd conmand{};
        if (Json::parseFromStream(reader, s, &parsedRoot, &errs)) // 检查 "cmd" 字段是否存在并转换为命令
        {
            if (parsedRoot.isMember("cmd") && parsedRoot["cmd"].isInt()) {
                conmand = intTocmd(parsedRoot["cmd"].asInt());
                switch (conmand)
                {
                case cmd::INITCONNECT: addClientToMap(parsedRoot["name"].asString(), channel);                          break;
                case cmd::DISCONNECT:  deleteClientFromMap(parsedRoot["name"].asString());                              break;
                case cmd::HEARTBEAT:   heartBeat(parsedRoot["name"].asString());                                                                     break;
                case cmd::SEND:        sendMsgToReceiver(parsedRoot["receiver"], parsedRoot["content"]);                 break;
                case cmd::SENDIMG:     saveImage(parsedRoot["image"].asString(), parsedRoot["image-name"].asString());  break;
                case cmd::SENDPDFFILE: savePdfFile(parsedRoot["content"].asString(), parsedRoot["filename"].asString()); break;
                default:               std::cout << "无当前命令" << std::endl; break;
                }
            }
            else {
                std::cout << "JSON 中缺少 'cmd' 字段或类型不正确" << std::endl;
                return;
                //channel->close(); //关闭连接
            }
        }
        else
        {
            std::cout << "解析失败" << errs << std::endl;
            return;
            //channel->close();
        }
    };
    server->start();
    return true;
}

void TServerWidget::heartBeat(const std::string& name)
{
    for(auto& client:clientMap)
    {
        if(client.first == name)
        {
            client.second.channel->write("connection still maintained");
            client.second.lastHeartbeatTime = std::chrono::steady_clock::now();
            //std::cout << name << " still online " << std::endl;
        }
    }
}

// 检查是否有客户端超时（30秒超时）
void TServerWidget::checkHeartbeats() {
    std::cout << __func__<< std::endl;
    auto now = std::chrono::steady_clock::now();
    auto timeout = std::chrono::seconds(30);
    std::string name = "";
    for (auto& client : clientMap) {
        if (now - client.second.lastHeartbeatTime > timeout) {
            std::cout << "Client " << client.first << " has timed out." << std::endl;
            client.second.channel->close();
            name = client.first;
        }
    }
    deleteClientFromMap(name);
}

void TServerWidget::deleteClientFromMap(const std::string& name)
{
    for(const auto& client:clientMap)
    {
        if(client.first == name)
        {
            std::cout << "关闭断连的端口" << std::endl;
            //client.second->close();
        }
    }
    m_pClientMapWidget->clear();
    int row_t = 0;
    clientMap.erase(name);
    for(const auto& client:clientMap)
    {
        m_pClientMapWidget->setItem(row_t, 0, new QTableWidgetItem(QString::fromStdString(client.first)));
        m_pClientMapWidget->setItem(row_t, 1, new QTableWidgetItem(QString::number(client.second.channel->fd())));
        row_t++;
        m_pClientMapWidget->raise();
        m_pClientMapWidget->show();
    }
    row = clientMap.size();
}

void TServerWidget::savePdfFile(const std::string& content, const std::string& fileName)
{
    std::cout << fileName << std::endl;
    QByteArray binaryData = QByteArray::fromBase64(QString::fromStdString(content).toUtf8());
    //QByteArray binaryData = QString::fromStdString(content).toUtf8();
    QFile outputFile(QString::fromStdString(fileName));
    if (outputFile.open(QIODevice::WriteOnly)) {
        outputFile.write(binaryData);
        outputFile.close();
        std::cout << "文件成功保存" << std::endl;
    }
    else {
        std::cout << "无法打开文件以写入" << std::endl;
        return;
    }
}

void TServerWidget::saveImage(const std::string& image, const std::string& imageName)
{
    std::cout << imageName << std::endl;
    stringToImage(image, imageName);
}

void TServerWidget::sendMsgToReceiver(Json::Value receivers, Json::Value content)
{
    Json::StreamWriterBuilder writer;
    std::string outputString = Json::writeString(writer, content);

    for (const auto& client : receivers)
    {
        std::cout << client.asString() << std::endl;
        auto recv = clientMap.find(client.asString());
            if (recv != clientMap.end()) recv->second.channel->write(outputString);
            else std::cerr << "Client not found: " << client.asString() << std::endl;
    }
}

void TServerWidget::addClientToMap(const std::string& name, const hv::SocketChannelPtr& channel)
{
    clientMap[name] = {channel, std::chrono::steady_clock::now()};
    m_pClientMapWidget->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(name)));
    m_pClientMapWidget->setItem(row, 1, new QTableWidgetItem(QString::number(channel->fd())));
    //m_pTipsBox->append(QString::fromStdString(name) + "  is online");
    row++;
}

void TServerWidget::stop()
{
    m_HeartBeatLoop->pause();//关闭检测心跳
    //SAFE_CLOSESOCKET(server->listenfd);
    //windows下套接字无效符INVALID_SOCKET,linux下-1。
    SAFE_DELETE(server);
}

TServerWidget::~TServerWidget()
{
    stop();
    clientMap.clear();
    incompleteMessageBuffer.clear();
    row = 0;
}

cmd TServerWidget::intTocmd(int i)
{
    return static_cast<cmd>(i);
}

void TServerWidget::initUI()
{
    m_pHost->move(50, 50);
    m_pPort->move(50, 100);
    m_pHost->setText("Host");
    m_pPort->setText("Port");

    m_pHostLine->move(90, 50);
    m_pHostLine->setText("0.0.0.0");
    m_pPortLine->move(90, 100);
    m_pPortLine->setText("9999");

    m_pStart->setText("Start");
    m_pEnd->setText("Close");
    m_pStart->move(50, 150);
    m_pEnd->move(200, 150);

    m_pTipsBox->resize(400, 100);
    m_pTipsBox->move(50, 200);
    //m_pTipsBox->setEnabled(false);

    m_pClientMapWidget->resize(180, 170);
    m_pClientMapWidget->move(310, 10);
    //m_pClientMapWidget->setEnabled(false);
    m_pClientMapWidget->setRowCount(20);
    m_pClientMapWidget->setColumnCount(2);
    m_pClientMapWidget->setHorizontalHeaderLabels({ "Client", "Fd" });
    m_pClientMapWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
}

bool TServerWidget::stringToImage(const std::string& base64Image, const std::string& name)
{
    QByteArray binaryData = QByteArray::fromBase64(QString::fromStdString(base64Image).toUtf8());
    if (binaryData.isEmpty()) {
        std::cout << "Base64解码失败，得到的二进制数据为空" << std::endl;
        return false;
    }
    QString dateTimeString = QDateTime::currentDateTime().toString("yyMMddhhmmss");
    QFile outputFile(dateTimeString + "_" + QString::fromStdString(name));//设置文件名称
    if (outputFile.open(QIODevice::WriteOnly)) {
        outputFile.write(binaryData);
        outputFile.close();
        std::cout << "图片解码成功并保存" << std::endl;
        return true;
    }
    else {
        std::cout << "无法打开文件以写入解码后的图片" << std::endl;
        return false;
    }
}
